home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-27  |  32.5 KB  |  1,166 lines

  1. /* screen.c - screen management
  2.  * 
  3.  *  Window Maker window manager
  4.  * 
  5.  *  Copyright (c) 1997, 1998 Alfredo K. Kojima
  6.  * 
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  20.  *  USA.
  21.  */
  22.  
  23. #include "wconfig.h"
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28.  
  29. #include <X11/Xlib.h>
  30. #include <X11/Xutil.h>
  31. #include <X11/Xatom.h>
  32. #ifdef SHAPE
  33. #include <X11/extensions/shape.h>
  34. #endif
  35. #ifdef KEEP_XKB_LOCK_STATUS     
  36. #include <X11/XKBlib.h>         
  37. #endif /* KEEP_XKB_LOCK_STATUS */
  38.  
  39. #include <wraster.h>
  40.  
  41. #include "WindowMaker.h"
  42. #include "def_pixmaps.h"
  43. #include "screen.h"
  44. #include "texture.h"
  45. #include "pixmap.h"
  46. #include "menu.h"
  47. #include "funcs.h"
  48. #include "actions.h"
  49. #include "properties.h"
  50. #include "dock.h"
  51. #include "resources.h"
  52. #include "workspace.h"
  53. #include "session.h"
  54. #include "balloon.h"
  55. #include "geomview.h"
  56. #ifdef KWM_HINTS
  57. # include "kwm.h"
  58. #endif
  59. #ifdef GNOME_STUFF
  60. # include "gnome.h"
  61. #endif
  62. #ifdef OLWM_HINTS
  63. # include "openlook.h"
  64. #endif
  65.  
  66. #include <proplist.h>
  67.  
  68. #include "defaults.h"
  69.  
  70.  
  71. #ifdef LITE
  72. #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
  73.         |SubstructureNotifyMask|PointerMotionMask \
  74.         |SubstructureRedirectMask|KeyPressMask|KeyReleaseMask)
  75. #else
  76. #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
  77.         |SubstructureNotifyMask|PointerMotionMask \
  78.         |SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
  79.         |KeyPressMask|KeyReleaseMask)
  80. #endif
  81.  
  82. /**** Global variables ****/
  83.  
  84. extern Cursor wCursor[WCUR_LAST];
  85. extern WPreferences wPreferences;
  86. extern Atom _XA_WINDOWMAKER_STATE;
  87. extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
  88.  
  89.  
  90. extern int wScreenCount;
  91.  
  92. #ifdef KEEP_XKB_LOCK_STATUS     
  93. extern int wXkbSupported;
  94. #endif
  95.  
  96. extern WDDomain *WDWindowMaker;
  97.  
  98.  
  99. /**** Local ****/
  100.  
  101. #define STIPPLE_WIDTH 2
  102. #define STIPPLE_HEIGHT 2
  103. static char STIPPLE_DATA[] = {0x02, 0x01};
  104.  
  105. static int CantManageScreen = 0;
  106.  
  107. static proplist_t dApplications = NULL;
  108. static proplist_t dWorkspace;
  109. static proplist_t dDock;
  110. static proplist_t dClip;
  111.  
  112.  
  113. static void
  114. make_keys()
  115. {
  116.     if (dApplications!=NULL)
  117.         return;
  118.  
  119.     dApplications = PLMakeString("Applications");
  120.     dWorkspace = PLMakeString("Workspace");
  121.     dDock = PLMakeString("Dock");
  122.     dClip = PLMakeString("Clip");
  123. }
  124.  
  125.  
  126. /*
  127.  *----------------------------------------------------------------------
  128.  * alreadyRunningError--
  129.  *     X error handler used to catch errors when trying to do
  130.  * XSelectInput() on the root window. These errors probably mean that
  131.  * there already is some other window manager running.
  132.  * 
  133.  * Returns:
  134.  *     Nothing, unless something really evil happens...
  135.  * 
  136.  * Side effects:
  137.  *     CantManageScreen is set to 1;
  138.  *---------------------------------------------------------------------- 
  139.  */
  140. static int 
  141. alreadyRunningError(Display *dpy, XErrorEvent *error)
  142. {
  143.     CantManageScreen = 1;
  144.     return -1;
  145. }
  146.  
  147.  
  148. /*
  149.  *---------------------------------------------------------------------- 
  150.  * allocButtonPixmaps--
  151.  *     Allocate pixmaps used on window operation buttons (those in the
  152.  * titlebar). The pixmaps are linked to the program. If XPM is supported
  153.  * XPM pixmaps are used otherwise, equivalent bitmaps are used.
  154.  * 
  155.  * Returns:
  156.  *     Nothing
  157.  * 
  158.  * Side effects:
  159.  *     Allocates shared pixmaps for the screen. These pixmaps should 
  160.  * not be freed by anybody.
  161.  *---------------------------------------------------------------------- 
  162.  */
  163. static void
  164. allocButtonPixmaps(WScreen *scr)
  165. {
  166.     WPixmap *pix;
  167.  
  168.     /* create predefined pixmaps */
  169.     pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
  170.     if (pix)
  171.       pix->shared = 1;
  172.     scr->b_pixmaps[WBUT_CLOSE] = pix;
  173.  
  174.     pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
  175.     if (pix)
  176.       pix->shared = 1;
  177.     scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
  178.  
  179.     pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
  180.     if (pix)
  181.       pix->shared = 1;
  182.     scr->b_pixmaps[WBUT_ICONIFY] = pix;
  183. #ifdef XKB_BUTTON_HINT
  184.     pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
  185.     if (pix)
  186.       pix->shared = 1;
  187.     scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
  188.     pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
  189.     if (pix)
  190.       pix->shared = 1;
  191.     scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
  192.     pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
  193.     if (pix)
  194.       pix->shared = 1;
  195.     scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
  196.     pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
  197.     if (pix)
  198.       pix->shared = 1;
  199.     scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
  200. #endif
  201.  
  202.     
  203.     pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
  204.     if (pix)
  205.       pix->shared = 1;
  206.     scr->b_pixmaps[WBUT_KILL] = pix;
  207. }
  208.  
  209.  
  210. static void
  211. draw_dot(WScreen *scr, Drawable d, int x, int y, GC gc)
  212. {
  213.     XSetForeground(dpy, gc, scr->black_pixel);
  214.     XDrawLine(dpy, d, gc, x, y, x+1, y);
  215.     XDrawPoint(dpy, d, gc, x, y+1);
  216.     XSetForeground(dpy, gc, scr->white_pixel);
  217.     XDrawLine(dpy, d, gc, x+2, y, x+2, y+1);
  218.     XDrawPoint(dpy, d, gc, x+1, y+1);
  219. }
  220.  
  221.  
  222. static WPixmap*
  223. make3Dots(WScreen *scr)
  224. {
  225.     WPixmap *wpix;
  226.     GC gc2, gc;
  227.     XGCValues gcv;
  228.     Pixmap pix, mask;
  229.     
  230.     gc = scr->copy_gc;
  231.     pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, 
  232.             wPreferences.icon_size,    scr->w_depth);
  233.     XSetForeground(dpy, gc, scr->black_pixel);
  234.     XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size, 
  235.            wPreferences.icon_size);
  236.     XSetForeground(dpy, gc, scr->white_pixel);
  237.     draw_dot(scr, pix, 4, wPreferences.icon_size-6, gc);
  238.     draw_dot(scr, pix, 9, wPreferences.icon_size-6, gc);
  239.     draw_dot(scr, pix, 14, wPreferences.icon_size-6, gc);
  240.  
  241.     mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, 
  242.              wPreferences.icon_size, 1);
  243.     gcv.foreground = 0;
  244.     gcv.graphics_exposures = False;
  245.     gc2 = XCreateGC(dpy, mask, GCForeground|GCGraphicsExposures, &gcv);
  246.     XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size, 
  247.            wPreferences.icon_size);
  248.     XSetForeground(dpy, gc2, 1);
  249.     XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size-6, 3, 2);
  250.     XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size-6, 3, 2);
  251.     XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size-6, 3, 2);
  252.     
  253.     XFreeGC(dpy, gc2);
  254.     
  255.     wpix = wPixmapCreate(scr, pix, mask);
  256.     wpix->shared = 1;
  257.  
  258.     return wpix;
  259. }
  260.  
  261.  
  262. static void
  263. allocGCs(WScreen *scr)
  264. {
  265.     XGCValues gcv;
  266.     XColor color;
  267.     unsigned long mtextcolor;
  268.     int gcm;
  269.  
  270.     scr->stipple_bitmap = 
  271.       XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH,
  272.                 STIPPLE_HEIGHT);
  273.  
  274.     gcv.stipple = scr->stipple_bitmap;
  275.     gcv.foreground = scr->white_pixel;
  276.     gcv.fill_style = FillStippled;
  277.     gcv.graphics_exposures = False;
  278.     gcm = GCForeground|GCStipple|GCFillStyle|GCGraphicsExposures;
  279.     scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
  280.  
  281.    
  282.     /* selected icon border GCs */
  283.     gcv.function    = GXcopy;
  284.     gcv.foreground  = scr->white_pixel;
  285.     gcv.background  = scr->black_pixel;
  286.     gcv.line_width  = 1;
  287.     gcv.line_style  = LineDoubleDash;
  288.     gcv.fill_style  = FillSolid;
  289.     gcv.dash_offset = 0;
  290.     gcv.dashes      = 4;
  291.     gcv.graphics_exposures = False;
  292.    
  293.     gcm = GCFunction | GCGraphicsExposures;
  294.     gcm |= GCForeground | GCBackground;
  295.     gcm |= GCLineWidth | GCLineStyle;
  296.     gcm |= GCFillStyle;
  297.     gcm |= GCDashOffset | GCDashList;
  298.  
  299.     scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
  300.  
  301.     gcm = GCForeground|GCGraphicsExposures;
  302.     
  303.     scr->menu_title_pixel[0] = scr->white_pixel;
  304.     gcv.foreground = scr->white_pixel;
  305.     gcv.graphics_exposures = False;
  306.     scr->menu_title_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
  307.  
  308.     scr->mtext_pixel = scr->black_pixel;
  309.     mtextcolor = gcv.foreground = scr->black_pixel;
  310.     scr->menu_entry_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
  311.  
  312.     /* selected menu entry GC */
  313.     gcm = GCForeground|GCBackground|GCGraphicsExposures;
  314.     gcv.foreground = scr->white_pixel;
  315.     gcv.background = scr->white_pixel;
  316.     gcv.graphics_exposures = False;
  317.     scr->select_menu_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
  318.  
  319.     /* disabled menu entry GC */
  320.     scr->dtext_pixel = scr->black_pixel;
  321.     gcm = GCForeground|GCBackground|GCStipple|GCGraphicsExposures;
  322.     gcv.stipple = scr->stipple_bitmap;
  323.     gcv.graphics_exposures = False;
  324.     scr->disabled_menu_entry_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
  325.  
  326.     /* frame GC */
  327.     wGetColor(scr, DEF_FRAME_COLOR, &color);
  328.     gcv.function = GXxor;
  329.     /* this will raise the probability of the XORed color being different
  330.      * of the original color in PseudoColor when not all color cells are
  331.      * initialized */
  332.     if (DefaultVisual(dpy, scr->screen)->class==PseudoColor)
  333.         gcv.plane_mask = (1<<(scr->depth-1))|1;
  334.     else
  335.     gcv.plane_mask = AllPlanes;
  336.     gcv.foreground = color.pixel;
  337.     if (gcv.foreground == 0)
  338.     gcv.foreground = 1;
  339.     gcv.line_width = DEF_FRAME_THICKNESS;
  340.     gcv.subwindow_mode = IncludeInferiors;
  341.     gcv.graphics_exposures = False;
  342.     scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground|GCGraphicsExposures
  343.                   |GCFunction|GCSubwindowMode|GCLineWidth
  344.                   |GCPlaneMask, &gcv);
  345.     
  346.     /* line GC */
  347.     gcv.foreground = color.pixel;
  348.  
  349.     if (gcv.foreground == 0)
  350.         /* XOR:ing with a zero is not going to be of much use, so
  351.            in that case, we somewhat arbitrarily xor with 17 instead. */
  352.         gcv.foreground = 17;
  353.  
  354.     gcv.function = GXxor;
  355.     gcv.subwindow_mode = IncludeInferiors;
  356.     gcv.line_width = 1;
  357.     gcv.cap_style = CapRound;
  358.     gcv.graphics_exposures = False;
  359.     gcm = GCForeground|GCFunction|GCSubwindowMode|GCLineWidth|GCCapStyle
  360.     |GCGraphicsExposures;
  361.     scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
  362.  
  363.     scr->line_pixel = gcv.foreground;
  364.     
  365.     /* copy GC */
  366.     gcv.foreground = scr->white_pixel;
  367.     gcv.background = scr->black_pixel;
  368.     gcv.graphics_exposures = False;
  369.     scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
  370.                  |GCGraphicsExposures, &gcv);
  371.  
  372.     /* window title text GC */
  373.     gcv.graphics_exposures = False;
  374.     scr->window_title_gc = XCreateGC(dpy, scr->w_win,GCGraphicsExposures,&gcv);
  375.  
  376.     /* icon title GC */
  377.     scr->icon_title_gc = XCreateGC(dpy, scr->w_win, GCGraphicsExposures, &gcv);
  378.  
  379.     /* clip title GC */
  380.     scr->clip_title_gc = XCreateGC(dpy, scr->w_win, GCGraphicsExposures, &gcv);
  381.  
  382.     /* move/size display GC */
  383.     gcv.graphics_exposures = False;
  384.     gcm = GCGraphicsExposures;
  385.     scr->info_text_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
  386.     
  387.     /* misc drawing GC */
  388.     gcv.graphics_exposures = False;
  389.     gcm = GCGraphicsExposures;
  390.     scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
  391.  
  392.     assert (scr->stipple_bitmap!=None);
  393.     
  394.     
  395.     /* mono GC */
  396.     scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
  397. }
  398.  
  399.  
  400.  
  401. static void
  402. createPixmaps(WScreen *scr)
  403. {
  404.     WPixmap *pix;
  405.     WMPixmap *wmpix;
  406.     RImage *image;
  407.     Pixmap p, m;
  408.  
  409.     /* load pixmaps */
  410.     pix = wPixmapCreateFromXBMData(scr, (char*)MENU_RADIO_INDICATOR_XBM_DATA,
  411.                    (char*)MENU_RADIO_INDICATOR_XBM_DATA,
  412.                    MENU_RADIO_INDICATOR_XBM_SIZE,
  413.                    MENU_RADIO_INDICATOR_XBM_SIZE,
  414.                    scr->black_pixel, scr->white_pixel);
  415.     if (pix!=NULL)
  416.       pix->shared = 1;
  417.     scr->menu_radio_indicator = pix;
  418.  
  419.  
  420.     pix = wPixmapCreateFromXBMData(scr, (char*)MENU_CHECK_INDICATOR_XBM_DATA,
  421.                    (char*)MENU_CHECK_INDICATOR_XBM_DATA,
  422.                    MENU_CHECK_INDICATOR_XBM_SIZE,
  423.                    MENU_CHECK_INDICATOR_XBM_SIZE,
  424.                    scr->black_pixel, scr->white_pixel);
  425.     if (pix!=NULL)
  426.       pix->shared = 1;
  427.     scr->menu_check_indicator = pix;
  428.  
  429.     pix = wPixmapCreateFromXBMData(scr, (char*)MENU_MINI_INDICATOR_XBM_DATA,
  430.                    (char*)MENU_MINI_INDICATOR_XBM_DATA,
  431.                    MENU_MINI_INDICATOR_XBM_SIZE,
  432.                    MENU_MINI_INDICATOR_XBM_SIZE,
  433.                    scr->black_pixel, scr->white_pixel);
  434.     if (pix!=NULL)
  435.       pix->shared = 1;
  436.     scr->menu_mini_indicator = pix;
  437.  
  438.     pix = wPixmapCreateFromXBMData(scr, (char*)MENU_HIDE_INDICATOR_XBM_DATA,
  439.                    (char*)MENU_HIDE_INDICATOR_XBM_DATA,
  440.                    MENU_HIDE_INDICATOR_XBM_SIZE,
  441.                    MENU_HIDE_INDICATOR_XBM_SIZE,
  442.                    scr->black_pixel, scr->white_pixel);
  443.     if (pix!=NULL)
  444.       pix->shared = 1;
  445.     scr->menu_hide_indicator = pix;
  446.  
  447.     pix = wPixmapCreateFromXBMData(scr, (char*)MENU_SHADE_INDICATOR_XBM_DATA,
  448.                                   (char*)MENU_SHADE_INDICATOR_XBM_DATA,
  449.                                   MENU_SHADE_INDICATOR_XBM_SIZE,
  450.                                   MENU_SHADE_INDICATOR_XBM_SIZE,
  451.                                   scr->black_pixel, scr->white_pixel);
  452.     if (pix!=NULL)
  453.       pix->shared = 1;
  454.     scr->menu_shade_indicator = pix;
  455.  
  456.  
  457.     image = wDefaultGetImage(scr, "Logo", "WMPanel");
  458.  
  459.     if (!image) {
  460.     wwarning(_("could not load logo image for panels: %s"),
  461.          RMessageForError(RErrorCode));
  462.     } else {
  463.     if (!RConvertImageMask(scr->rcontext, image, &p, &m, 128)) {
  464.         wwarning(_("error making logo image for panel:%s"), RMessageForError(RErrorCode));
  465.     } else {
  466.         wmpix = WMCreatePixmapFromXPixmaps(scr->wmscreen, p, m,
  467.                            image->width, image->height, 
  468.                            scr->depth);
  469.         WMSetApplicationIconImage(scr->wmscreen, wmpix); 
  470.         WMReleasePixmap(wmpix);
  471.     }
  472.     RDestroyImage(image);
  473.     }
  474.  
  475.     scr->dock_dots = make3Dots(scr);
  476.  
  477.     /* titlebar button pixmaps */
  478.     allocButtonPixmaps(scr);
  479. }
  480.  
  481.  
  482. /*
  483.  *----------------------------------------------------------------------
  484.  * createInternalWindows--
  485.  *     Creates some windows used internally by the program. One to
  486.  * receive input focus when no other window can get it and another
  487.  * to display window geometry information during window resize/move.
  488.  * 
  489.  * Returns:
  490.  *     Nothing
  491.  * 
  492.  * Side effects:
  493.  *     Windows are created and some colors are allocated for the
  494.  * window background.
  495.  *---------------------------------------------------------------------- 
  496.  */
  497. static void
  498. createInternalWindows(WScreen *scr)
  499. {
  500.     int vmask;
  501.     XSetWindowAttributes attribs;
  502.     
  503.     /* InputOnly window to get the focus when no other window can get it */
  504.     vmask = CWEventMask|CWOverrideRedirect;
  505.     attribs.event_mask = KeyPressMask|FocusChangeMask;
  506.     attribs.override_redirect = True;
  507.     scr->no_focus_win=XCreateWindow(dpy,scr->root_win,-10, -10, 4, 4, 0, 0,
  508.                     InputOnly,CopyFromParent, vmask, &attribs);
  509.     XSelectInput(dpy, scr->no_focus_win, KeyPressMask|KeyReleaseMask);
  510.     XMapWindow(dpy, scr->no_focus_win);
  511.  
  512.     XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
  513.  
  514.     /* shadow window for dock buttons */
  515.     vmask = CWBorderPixel|CWBackPixmap|CWBackPixel|CWCursor|CWSaveUnder|CWOverrideRedirect;
  516.     attribs.border_pixel = scr->black_pixel;
  517.     attribs.save_under = True;
  518.     attribs.override_redirect = True;
  519.     attribs.background_pixmap = None;
  520.     attribs.background_pixel = scr->white_pixel;
  521.     attribs.cursor = wCursor[WCUR_DEFAULT];
  522.     vmask |= CWColormap;
  523.     attribs.colormap = scr->w_colormap;
  524.     scr->dock_shadow =
  525.       XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size, 
  526.             wPreferences.icon_size, 0, scr->w_depth, CopyFromParent, 
  527.             scr->w_visual, vmask, &attribs);
  528.  
  529.     /* workspace name balloon for clip */
  530.     vmask = CWBackPixel|CWSaveUnder|CWOverrideRedirect|CWColormap
  531.     |CWBorderPixel;
  532.     attribs.save_under = True;
  533.     attribs.override_redirect = True;
  534.     attribs.colormap = scr->w_colormap;
  535.     attribs.background_pixel = scr->icon_back_texture->normal.pixel;
  536.     attribs.border_pixel = 0; /* do not care */
  537.     scr->clip_balloon =
  538.       XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
  539.             CopyFromParent, scr->w_visual, vmask, &attribs);
  540.  
  541.     
  542.     /* workspace name */
  543.     vmask = CWBackPixel|CWSaveUnder|CWOverrideRedirect|CWColormap
  544.     |CWBorderPixel;
  545.     attribs.save_under = True;
  546.     attribs.override_redirect = True;
  547.     attribs.colormap = scr->w_colormap;
  548.     attribs.background_pixel = scr->icon_back_texture->normal.pixel;
  549.     attribs.border_pixel = 0; /* do not care */
  550.     scr->workspace_name =
  551.       XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
  552.             CopyFromParent, scr->w_visual, vmask, &attribs);
  553.  
  554.     /*
  555.      * If the window is clicked without having ButtonPress selected, the
  556.      * resulting event will have event.xbutton.window == root.
  557.      */
  558.     XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
  559. }
  560.  
  561.  
  562. #if 0
  563. static Bool
  564. aquireManagerSelection(WScreen *scr)
  565. {
  566.     char buffer[32];
  567.     XEvent ev;
  568.     Time timestamp;
  569.  
  570.     sprintf(buffer, "WM_S%i", scr->screen);
  571.     scr->managerAtom = XInternAtom(dpy, buffer, False);
  572.  
  573.     /* for race-conditions... */
  574.     XGrabServer(dpy);
  575.  
  576.     /* if there is another manager running, don't try to replace it
  577.      * (for now, at least) */
  578.     if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
  579.     XUngrabServer(dpy);
  580.     return False;
  581.     }
  582.  
  583.     /* become the manager for this screen */
  584.  
  585.     scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1,
  586.                          0, 0, 0);
  587.  
  588.     XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
  589.     /* get a timestamp */
  590.     XChangeProperty(dpy, scr->managerWindow, scr->managerAtom,
  591.             XA_INTEGER, 32, PropModeAppend, NULL, 0);
  592.     while (1) {
  593.     XWindowEvent(dpy, scr->managerWindow, &ev);
  594.     if (ev.type == PropertyNotify) {
  595.         timestamp = ev.xproperty.time;
  596.         break;
  597.     }
  598.     }
  599.     XSelectInput(dpy, scr->managerWindow, NoEvents);
  600.     XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
  601.  
  602.     XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
  603.  
  604.     XUngrabServer(dpy);
  605.  
  606.     /* announce our arrival */
  607.  
  608.     ev.xclient.type = ClientMessage;
  609.     ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
  610.     ev.xclient.destination = scr->root_win;
  611.     ev.xclient.format = 32;
  612.     ev.xclient.data.l[0] = timestamp;
  613.     ev.xclient.data.l[1] = scr->managerAtom;
  614.     ev.xclient.data.l[2] = scr->managerWindow;
  615.     ev.xclient.data.l[3] = 0;
  616.     ev.xclient.data.l[4] = 0;
  617.  
  618.     XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
  619.     XSync(dpy, False);
  620.  
  621.     return True;
  622. }
  623. #endif
  624.  
  625. /*
  626.  *----------------------------------------------------------------------
  627.  * wScreenInit--
  628.  *     Initializes the window manager for the given screen and 
  629.  * allocates a WScreen descriptor for it. Many resources are allocated
  630.  * for the screen and the root window is setup appropriately.
  631.  *
  632.  * Returns:
  633.  *     The WScreen descriptor for the screen.
  634.  * 
  635.  * Side effects:
  636.  *     Many resources are allocated and the IconSize property is
  637.  * set on the root window.
  638.  *    The program can be aborted if some fatal error occurs.
  639.  * 
  640.  * TODO: User specifiable visual.
  641.  *---------------------------------------------------------------------- 
  642.  */
  643. WScreen*
  644. wScreenInit(int screen_number)
  645. {
  646.     WScreen *scr;
  647.     XIconSize icon_size[1];
  648.     RContextAttributes rattr;
  649.     extern int wVisualID;
  650.     long event_mask;
  651.     WMColor *color;
  652.     XErrorHandler oldHandler;
  653.  
  654.     scr = wmalloc(sizeof(WScreen));
  655.     memset(scr, 0, sizeof(WScreen));
  656.  
  657.     scr->stacking_list = WMCreateTreeBag();
  658.     
  659.     /* initialize globals */
  660.     scr->screen = screen_number;
  661.     scr->root_win = RootWindow(dpy, screen_number);
  662.     scr->depth = DefaultDepth(dpy, screen_number);
  663.     scr->colormap = DefaultColormap(dpy, screen_number);
  664.  
  665.     scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
  666.     scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
  667.  
  668.     scr->usableArea.x2 = scr->scr_width;
  669.     scr->usableArea.y2 = scr->scr_height;
  670.     scr->totalUsableArea.x2 = scr->scr_width;
  671.     scr->totalUsableArea.y2 = scr->scr_height;
  672.  
  673. #if 0
  674.     if (!aquireManagerSelection(scr)) {
  675.     free(scr);
  676.  
  677.     return NULL;
  678.     }
  679. #endif
  680.     CantManageScreen = 0;
  681.     oldHandler = XSetErrorHandler((XErrorHandler)alreadyRunningError);
  682.  
  683.     event_mask = EVENT_MASK;
  684.  
  685.     if (wPreferences.disable_root_mouse) {
  686.     event_mask &= ~(ButtonPressMask|ButtonReleaseMask);
  687.     }
  688.     
  689.     XSelectInput(dpy, scr->root_win, event_mask);
  690.  
  691. #ifdef KEEP_XKB_LOCK_STATUS     
  692.     /* Only GroupLock doesn't work correctly in my system since right-alt
  693.      * can change mode while holding it too - ]d
  694.      */
  695.     if (wXkbSupported) {
  696.         XkbSelectEvents(dpy,XkbUseCoreKbd,
  697.                 XkbStateNotifyMask,
  698.                 XkbStateNotifyMask);
  699.     }
  700. #endif /* KEEP_XKB_LOCK_STATUS */
  701.  
  702.     XSync(dpy, False);
  703.     XSetErrorHandler(oldHandler);
  704.     
  705.     if (CantManageScreen) {
  706.     free(scr);
  707.     return NULL;
  708.     }
  709.  
  710. #ifndef DEFINABLE_CURSOR
  711.     XDefineCursor(dpy, scr->root_win, wCursor[WCUR_DEFAULT]);
  712. #endif
  713.  
  714.     /* screen descriptor for raster graphic library */
  715.     rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_StandardColormap;
  716.     rattr.render_mode = wPreferences.no_dithering 
  717.                 ? RBestMatchRendering
  718.                 : RDitheredRendering;
  719.  
  720.     /* if the std colormap stuff works ok, this will be ignored */
  721.     rattr.colors_per_channel = wPreferences.cmap_size;
  722.     if (rattr.colors_per_channel<2)
  723.     rattr.colors_per_channel = 2;
  724.  
  725.     /* will only be accounted for in PseudoColor */
  726.     rattr.standard_colormap_mode = RCreateStdColormap;
  727.  
  728.     if (wVisualID>=0) {
  729.     rattr.flags |= RC_VisualID;
  730.     rattr.visualid = wVisualID;
  731.     }
  732.     
  733.     scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
  734.  
  735.     if (!scr->rcontext && RErrorCode == RERR_STDCMAPFAIL) {
  736.     wwarning(RMessageForError(RErrorCode));
  737.  
  738.     rattr.flags &= ~RC_StandardColormap;
  739.     rattr.standard_colormap_mode = RUseStdColormap;
  740.  
  741.     scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
  742.     }
  743.  
  744.     if (!scr->rcontext) {
  745.     wwarning(_("could not initialize graphics library context: %s"),
  746.          RMessageForError(RErrorCode));
  747.     wAbort(False);
  748.     } else {
  749.     char **formats;
  750.     int i = 0;
  751.  
  752.     formats = RSupportedFileFormats();
  753.     if (formats) {
  754.         for (i=0; formats[i]!=NULL; i++) {
  755.         if (strcmp(formats[i], "TIFF")==0) {
  756.             scr->flags.supports_tiff = 1;
  757.             break;
  758.         }
  759.         }
  760.     }
  761.     }
  762.     
  763.     scr->w_win = scr->rcontext->drawable;
  764.     scr->w_visual = scr->rcontext->visual;
  765.     scr->w_depth = scr->rcontext->depth;
  766.     scr->w_colormap = scr->rcontext->cmap;
  767.  
  768.     scr->black_pixel = scr->rcontext->black;
  769.     scr->white_pixel = scr->rcontext->white;    
  770.  
  771.     /* create screen descriptor for WINGs */
  772.     scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number,
  773.                            scr->rcontext);
  774.  
  775.     if (!scr->wmscreen) {
  776.     wfatal(_("could not do initialization of WINGs widget set"));
  777.  
  778.     return NULL;
  779.     }
  780.  
  781.     color = WMGrayColor(scr->wmscreen);
  782.     scr->light_pixel = WMColorPixel(color);
  783.     WMReleaseColor(color);
  784.  
  785.     color = WMDarkGrayColor(scr->wmscreen);
  786.     scr->dark_pixel = WMColorPixel(color);
  787.     WMReleaseColor(color);
  788.  
  789.     {
  790.     XColor xcol;
  791.     /* frame boder color */
  792.     wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
  793.     scr->frame_border_pixel = xcol.pixel;
  794.     }
  795.  
  796.     /* create GCs with default values */
  797.     allocGCs(scr);
  798.  
  799.     
  800.     /* for our window manager info notice board. Need to
  801.      * create before reading the defaults, because it will be used there. 
  802.      */
  803.     scr->info_window = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 10, 10, 
  804.                        0, 0, 0);
  805.     
  806.     /* read defaults for this screen */
  807.     wReadDefaults(scr, WDWindowMaker->dictionary);
  808.  
  809.     createInternalWindows(scr);
  810.  
  811. #ifdef KWM_HINTS
  812.     wKWMInitStuff(scr);
  813. #endif
  814.  
  815. #ifdef GNOME_STUFF
  816.     wGNOMEInitStuff(scr);
  817. #endif
  818.  
  819. #ifdef OLWM_HINTS
  820.     wOLWMInitStuff(scr);
  821. #endif
  822.  
  823.     /* create initial workspace */
  824.     wWorkspaceNew(scr);
  825.  
  826.     /* create shared pixmaps */
  827.     createPixmaps(scr);
  828.  
  829.     /* set icon sizes we can accept from clients */
  830.     icon_size[0].min_width = 8;
  831.     icon_size[0].min_height = 8;
  832.     icon_size[0].max_width = wPreferences.icon_size-4;
  833.     icon_size[0].max_height = wPreferences.icon_size-4;
  834.     icon_size[0].width_inc = 1;
  835.     icon_size[0].height_inc = 1;
  836.     XSetIconSizes(dpy, scr->root_win, icon_size, 1);
  837.  
  838.     /* setup WindowMaker protocols property in the root window*/
  839.     PropSetWMakerProtocols(scr->root_win);
  840.  
  841.     /* setup our noticeboard */
  842.     XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
  843.             XA_WINDOW, 32, PropModeReplace, 
  844.             (unsigned char*)&scr->info_window, 1);
  845.     XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
  846.             XA_WINDOW, 32, PropModeReplace, 
  847.             (unsigned char*)&scr->info_window, 1);
  848.  
  849.  
  850. #ifdef BALLOON_TEXT
  851.     /* initialize balloon text stuff */
  852.     wBalloonInitialize(scr);
  853. #endif
  854.     
  855.     scr->info_text_font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
  856.                          
  857.  
  858.     scr->gview = WCreateGeometryView(scr->wmscreen);
  859.     WMRealizeWidget(scr->gview);
  860.  
  861.     wScreenUpdateUsableArea(scr);
  862.  
  863.     return scr;
  864. }
  865.  
  866.  
  867. void
  868. wScreenUpdateUsableArea(WScreen *scr)
  869. {
  870. #ifdef GNOME_STUFF
  871.     WReservedArea *area;
  872. #endif
  873.  
  874.     scr->totalUsableArea = scr->usableArea;
  875.  
  876.  
  877.     if (scr->dock && (!scr->dock->lowered 
  878.               || wPreferences.no_window_over_dock)) {
  879.  
  880.     int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
  881.  
  882.     if (scr->dock->on_right_side) {
  883.         scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2,
  884.                       scr->scr_width - offset);
  885.     } else {
  886.         scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, offset);
  887.     }
  888.     }
  889.     
  890.     if (wPreferences.no_window_over_icons) {
  891.     if (wPreferences.icon_yard & IY_VERT) {
  892.  
  893.         if (!(wPreferences.icon_yard & IY_RIGHT)) {
  894.         scr->totalUsableArea.x1 += wPreferences.icon_size;
  895.         } else {
  896.         scr->totalUsableArea.x2 -= wPreferences.icon_size;
  897.         }
  898.     } else {
  899.  
  900.         if (wPreferences.icon_yard & IY_TOP) {
  901.         scr->totalUsableArea.y1 += wPreferences.icon_size;
  902.         } else {
  903.         scr->totalUsableArea.y2 -= wPreferences.icon_size;
  904.         }
  905.     }
  906.     }
  907.  
  908. #ifdef KWM_HINTS
  909.     {
  910.     WArea area;
  911.  
  912.     if (wKWMGetUsableArea(scr, &area)) {
  913.         scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, area.x1);
  914.         scr->totalUsableArea.y1 = WMAX(scr->totalUsableArea.y1, area.y1);
  915.         scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, area.x2);
  916.         scr->totalUsableArea.y2 = WMIN(scr->totalUsableArea.y2, area.y2);
  917.     }
  918.     }
  919. #endif
  920.  
  921. #ifdef GNOME_STUFF
  922.     area = scr->reservedAreas;    
  923.  
  924.     while (area) {
  925.     int th, bh;
  926.     int lw, rw;
  927.     int w, h;
  928.  
  929.     w = area->area.x2 - area->area.x1;
  930.     h = area->area.y2 - area->area.y1;
  931.  
  932.     th = area->area.y1;
  933.     bh = scr->scr_height - area->area.y2;
  934.     lw = area->area.x1;
  935.     rw = scr->scr_width - area->area.x2;
  936.  
  937.     if (WMIN(th, bh) < WMIN(lw, rw)) {
  938.         /* horizontal */
  939.         if (th < bh) {
  940.         /* on top */
  941.         if (scr->totalUsableArea.y1 < area->area.y2)
  942.             scr->totalUsableArea.y1 = area->area.y2;
  943.         } else {
  944.         /* on bottom */
  945.         if (scr->totalUsableArea.y2 > area->area.y1)
  946.             scr->totalUsableArea.y2 = area->area.y1;
  947.         }
  948.     } else {
  949.         /* vertical */
  950.         if (lw < rw) {
  951.         /* on left */
  952.         if (scr->totalUsableArea.x1 < area->area.x2)
  953.             scr->totalUsableArea.x1 = area->area.x2;
  954.         } else {
  955.         /* on right */
  956.         if (scr->totalUsableArea.x2 > area->area.x1)
  957.             scr->totalUsableArea.x2 = area->area.x1;
  958.         }
  959.     }
  960.  
  961.     area = area->next;
  962.     }
  963. #endif /* GNOME_STUFF */
  964.  
  965.     if (scr->totalUsableArea.x2 - scr->totalUsableArea.x1 < scr->scr_width/2) {
  966.     scr->totalUsableArea.x2 = scr->usableArea.x2;
  967.     scr->totalUsableArea.x1 = scr->usableArea.x1;
  968.     }
  969.     if (scr->totalUsableArea.y2 - scr->totalUsableArea.y1 < scr->scr_height/2) {
  970.     scr->totalUsableArea.y2 = scr->usableArea.y2;
  971.     scr->totalUsableArea.y1 = scr->usableArea.y1;
  972.     }
  973.  
  974. #ifdef not_used
  975. #ifdef KWM_HINTS
  976.     {
  977.     int i;
  978.  
  979.     for (i = 0; i < scr->workspace_count; i++) {
  980.         wKWMSetUsableAreaHint(scr, i);
  981.     }
  982.     }
  983. #endif
  984. #endif
  985. }
  986.  
  987.  
  988. void
  989. wScreenRestoreState(WScreen *scr)
  990. {
  991.     proplist_t state;
  992.     char *path;
  993.  
  994.     
  995. #ifndef LITE
  996.     OpenRootMenu(scr, -10000, -10000, False);
  997.     wMenuUnmap(scr->root_menu);
  998. #endif
  999.  
  1000.     make_keys();
  1001.  
  1002.     if (wScreenCount == 1)
  1003.     path = wdefaultspathfordomain("WMState");
  1004.     else {
  1005.     char buf[16];
  1006.     sprintf(buf, "WMState.%i", scr->screen);
  1007.     path = wdefaultspathfordomain(buf);
  1008.     }
  1009.     scr->session_state = PLGetProplistWithPath(path);
  1010.     free(path);
  1011.     if (!scr->session_state && wScreenCount>1) {
  1012.     char buf[16];
  1013.     sprintf(buf, "WMState.%i", scr->screen);
  1014.     path = wdefaultspathfordomain(buf);
  1015.     scr->session_state = PLGetProplistWithPath(path);
  1016.     free(path);
  1017.     }
  1018.  
  1019.     if (!wPreferences.flags.noclip) {
  1020.         state = PLGetDictionaryEntry(scr->session_state, dClip);
  1021.         scr->clip_icon = wClipRestoreState(scr, state);
  1022.     }
  1023.  
  1024.     wWorkspaceRestoreState(scr);
  1025.  
  1026. #ifdef VIRTUAL_DESKTOP
  1027.         /*
  1028.          *      * create inputonly windows at the border of screen
  1029.          *           */
  1030.         wWorkspaceManageEdge(scr);
  1031. #endif
  1032.  
  1033.     if (!wPreferences.flags.nodock) {
  1034.         state = PLGetDictionaryEntry(scr->session_state, dDock);
  1035.         scr->dock = wDockRestoreState(scr, state, WM_DOCK);
  1036.     }
  1037.  
  1038.     wScreenUpdateUsableArea(scr);
  1039. }
  1040.  
  1041.  
  1042. void
  1043. wScreenSaveState(WScreen *scr)
  1044. {
  1045.     WWorkspaceState wstate;
  1046.     WWindow *wwin;
  1047.     char *str;
  1048.     proplist_t path, old_state, foo;
  1049.     CARD32 data[2];
  1050.  
  1051.  
  1052.     make_keys();
  1053.  
  1054. /*
  1055.  * Save current workspace, so can go back to it upon restart.
  1056.  */
  1057.     wstate.workspace = scr->current_workspace;
  1058.  
  1059.     data[0] = wstate.flags;
  1060.     data[1] = wstate.workspace;
  1061.  
  1062.     XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_STATE,
  1063.                     _XA_WINDOWMAKER_STATE, 32, PropModeReplace,
  1064.                     (unsigned char *) data, 2);
  1065.     
  1066.     /* save state of windows */
  1067.     wwin = scr->focused_window;
  1068.     while (wwin) {
  1069.     wWindowSaveState(wwin);
  1070.     wwin = wwin->prev;
  1071.     }
  1072.  
  1073.  
  1074.     if (wPreferences.flags.noupdates)
  1075.     return;
  1076.  
  1077.  
  1078.     old_state = scr->session_state;
  1079.     scr->session_state = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
  1080.  
  1081.     PLSetStringCmpHook(NULL);
  1082.  
  1083.     /* save dock state to file */
  1084.     if (!wPreferences.flags.nodock) {
  1085.         wDockSaveState(scr, old_state);
  1086.     } else {
  1087.         if ((foo = PLGetDictionaryEntry(old_state, dDock))!=NULL) {
  1088.             PLInsertDictionaryEntry(scr->session_state, dDock, foo);
  1089.         }
  1090.     }
  1091.     if (!wPreferences.flags.noclip) {
  1092.         wClipSaveState(scr);
  1093.     } else {
  1094.         if ((foo = PLGetDictionaryEntry(old_state, dClip))!=NULL) {
  1095.             PLInsertDictionaryEntry(scr->session_state, dClip, foo);
  1096.         }
  1097.     }
  1098.  
  1099.     wWorkspaceSaveState(scr, old_state);
  1100.  
  1101.     if (wPreferences.save_session_on_exit) {
  1102.         wSessionSaveState(scr);
  1103.     } else {
  1104.         if ((foo = PLGetDictionaryEntry(old_state, dApplications))!=NULL) {
  1105.             PLInsertDictionaryEntry(scr->session_state, dApplications, foo);
  1106.         }
  1107.         if ((foo = PLGetDictionaryEntry(old_state, dWorkspace))!=NULL) {
  1108.             PLInsertDictionaryEntry(scr->session_state, dWorkspace, foo);
  1109.         }
  1110.     }
  1111.  
  1112.     /* clean up */
  1113.     PLSetStringCmpHook(StringCompareHook);
  1114.  
  1115.     wMenuSaveState(scr);
  1116.  
  1117.     if (wScreenCount == 1)
  1118.     str = wdefaultspathfordomain("WMState");
  1119.     else {
  1120.     char buf[16];
  1121.     sprintf(buf, "WMState.%i", scr->screen);
  1122.     str = wdefaultspathfordomain(buf);
  1123.     }
  1124.     path = PLMakeString(str);
  1125.     free(str);
  1126.     PLSetFilename(scr->session_state, path);
  1127.     if (!PLSave(scr->session_state, YES)) {
  1128.     wsyserror(_("could not save session state in %s"), PLGetString(path));
  1129.     }
  1130.     PLRelease(path);
  1131.     PLRelease(old_state);
  1132. }
  1133.  
  1134.  
  1135.  
  1136. int
  1137. wScreenBringInside(WScreen *scr, int *x, int *y, int width, int height)
  1138. {
  1139.     int moved = 0;
  1140.     int tol_w, tol_h;
  1141.  
  1142.     if (width > 20)
  1143.     tol_w = width/2;
  1144.     else
  1145.     tol_w = 20;
  1146.  
  1147.     if (height > 20)
  1148.     tol_h = height/2;
  1149.     else
  1150.     tol_h = 20;
  1151.  
  1152.     if (*x+width < 10)
  1153.     *x = -tol_w, moved = 1;
  1154.     else if (*x >= scr->scr_width - 10)
  1155.     *x = scr->scr_width - tol_w - 1, moved = 1;
  1156.  
  1157.     if (*y < -height + 10)
  1158.     *y = -tol_h, moved = 1;
  1159.     else if (*y >= scr->scr_height - 10)
  1160.     *y = scr->scr_height - tol_h - 1, moved = 1;
  1161.  
  1162.     return moved;
  1163. }
  1164.  
  1165.  
  1166.